#ifndef PACKET_H_
#define PACKET_H_

//-----------------------------------------------------------------------------

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned char* LPBYTE;
typedef unsigned short* LPWORD;
typedef unsigned long* LPDWORD;
typedef unsigned int u32;
typedef long long __int64;

#define LOWORD(l)				((WORD)(l))
#define HIWORD(l)				((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define LOBYTE(w)				((BYTE)(w))
#define HIBYTE(w)				((BYTE)(((WORD)(w) >> 8) & 0xFF))
#define MAKEWORD(low, high)		((WORD)((((WORD)(high)) << 8) | ((BYTE)(low))))

#include <string.h>
#include "stdio.h"
#include <wchar.h>
#include <stdint.h>

#ifndef _VECTOR_
    #include <vector>
#endif

//-----------------------------------------------------------------------------

#pragma pack(push, 1)
    struct tPacket
    {
            WORD size;
            WORD opcode;
            BYTE securityCount;
            BYTE securityCRC;
            BYTE data[8186];
    };
#pragma pack(pop)

//-----------------------------------------------------------------------------

// Packet building class
class PacketBuilder
{
private:
        BYTE data[8192];
        WORD size;

public:
        // Ctor
        PacketBuilder();

        // Dtor
        ~PacketBuilder();

        //--------------------------------------------

        // Clear the packet data
        void Clear();

        //--------------------------------------------

        // Get the packet buffer
        tPacket * GetPacket();

        // Return the packet size
        WORD GetSize();

        //--------------------------------------------

        // Set the packet's opcode
        void SetOpcode(WORD opcode);

        //--------------------------------------------

        // Add data function
        void AppendByte(BYTE byte);

        // Add data function
        void AppendWord(WORD word);

        // Add data function
        void AppendDword(DWORD dword);

        // Append a string
        void AppendString(const char * str);

        // Append a wide string
        void AppendWideString(const wchar_t * str);

        // Append a string
        void AppendArray(int length, void * buffer);

        // Append a double
        void AppendDouble(double value);

        // Append a double
        void AppendFloat(float value);

        // Copy this packet into another packet
        void Copy(tPacket * outPacket);
};

//-----------------------------------------------------------------------------

// Packet reading class
class PacketReader
{
private:
        tPacket * packet;

public:
        PacketReader();
        PacketReader(tPacket * p);
        ~PacketReader();

        int index;

        //--------------------------------------------

        // Set the packet pointer
        void SetPacket(tPacket * p);

        //--------------------------------------------

        // Returns the packet's opcode
        WORD GetPacketOpcode();

        // Returns the packet's size
        WORD GetPacketSize();

        // Returns how much data can be read
        int GetBytesLeft();

        // Returns the packet associated with this reader
        tPacket * GetPacket();

        // Returns the current index the reader is at
        DWORD GetIndex();

        //--------------------------------------------

        // Read in specific data types
        BYTE ReadByte();

        // Read in specific data types
        WORD ReadWord();

        // Read in specific data types
        DWORD ReadDword();

        // Read in specific data types
        int ReadInt();

        // Read in specific data types
        void ReadArray(int size, void * outBuffer);

        // Read in specific data types
        void ReadString(int size, char * outBuffer);

        // Read in specific data types
        void ReadWideString(int size, wchar_t * outBuffer);

        // Read in specific data types
        double ReadDouble();

        // Read in specific data types
        float ReadFloat();

        // Read in specific data types
        __int64 Read64();
};

//-----------------------------------------------------------------------------

#endif
